package com.lifeverse.entity;

import com.lifeverse.entity.enums.HealthStatus;
import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.time.LocalDateTime;
import java.util.Map;

/**
 * 服务发现实体
 */
@Entity
@Table(name = "service_discovery")
@Data
@EqualsAndHashCode(callSuper = true)
public class ServiceDiscovery extends BaseEntity {

    /**
     * 服务名称
     */
    @Column(nullable = false, length = 100)
    private String serviceName;

    /**
     * 服务实例ID
     */
    @Column(nullable = false, length = 100, unique = true)
    private String instanceId;

    /**
     * 服务主机地址
     */
    @Column(nullable = false, length = 100)
    private String host;

    /**
     * 服务端口
     */
    @Column(nullable = false)
    private Integer port;

    /**
     * 服务版本
     */
    @Column(length = 50)
    private String version;

    /**
     * 服务状态
     */
    @Enumerated(EnumType.STRING)
    @Column(nullable = false)
    private HealthStatus status;

    /**
     * 服务元数据
     */
    @ElementCollection
    @CollectionTable(name = "service_metadata", joinColumns = @JoinColumn(name = "service_id"))
    @MapKeyColumn(name = "meta_key")
    @Column(name = "meta_value")
    private Map<String, String> metadata;

    /**
     * 服务标签
     */
    @ElementCollection
    @CollectionTable(name = "service_tags", joinColumns = @JoinColumn(name = "service_id"))
    @Column(name = "tag")
    private java.util.Set<String> tags;

    /**
     * 健康检查URL
     */
    @Column(length = 500)
    private String healthCheckUrl;

    /**
     * 注册时间
     */
    @Column(nullable = false)
    private LocalDateTime registeredAt;

    /**
     * 最后心跳时间
     */
    @Column(nullable = false)
    private LocalDateTime lastHeartbeat;

    /**
     * 心跳间隔（秒）
     */
    @Column(nullable = false)
    private Integer heartbeatInterval = 30;

    /**
     * 心跳超时时间（秒）
     */
    @Column(nullable = false)
    private Integer heartbeatTimeout = 90;

    /**
     * 是否启用
     */
    @Column(nullable = false)
    private Boolean enabled = true;

    /**
     * 权重（负载均衡用）
     */
    @Column(nullable = false)
    private Integer weight = 100;

    /**
     * 服务描述
     */
    @Column(columnDefinition = "TEXT")
    private String description;

    /**
     * 服务环境（dev, test, prod等）
     */
    @Column(length = 50)
    private String environment;

    /**
     * 服务区域
     */
    @Column(length = 50)
    private String region;

    /**
     * 服务可用区
     */
    @Column(length = 50)
    private String availabilityZone;

    /**
     * 获取服务地址
     */
    public String getServiceAddress() {
        return host + ":" + port;
    }

    /**
     * 判断服务是否可用
     */
    public boolean isAvailable() {
        return enabled && status != null && status.isNormal() && !isHeartbeatExpired();
    }

    /**
     * 判断心跳是否过期
     */
    public boolean isHeartbeatExpired() {
        if (lastHeartbeat == null) return true;
        
        LocalDateTime expireTime = lastHeartbeat.plusSeconds(heartbeatTimeout);
        return LocalDateTime.now().isAfter(expireTime);
    }

    /**
     * 更新心跳
     */
    public void updateHeartbeat() {
        this.lastHeartbeat = LocalDateTime.now();
        if (this.status == HealthStatus.DOWN || this.status == HealthStatus.UNKNOWN) {
            this.status = HealthStatus.HEALTHY;
        }
    }

    /**
     * 标记服务为不可用
     */
    public void markAsUnavailable(String reason) {
        this.status = HealthStatus.DOWN;
        this.enabled = false;
        if (this.metadata == null) {
            this.metadata = new java.util.HashMap<>();
        }
        this.metadata.put("unavailable_reason", reason);
        this.metadata.put("unavailable_time", LocalDateTime.now().toString());
    }

    /**
     * 恢复服务可用性
     */
    public void restore() {
        this.status = HealthStatus.HEALTHY;
        this.enabled = true;
        this.lastHeartbeat = LocalDateTime.now();
        if (this.metadata != null) {
            this.metadata.remove("unavailable_reason");
            this.metadata.remove("unavailable_time");
        }
    }
}